/**
 *  @file Quaternion.hpp
 *
 *  @date 05.12.2011
 *  @author Thomas Wiemann
 */

#ifndef __QUATERNION_HPP__
#define __QUATERNION_HPP__

#include "Global.hpp"
#include "math/Vertex.hpp"
#include "math/Vertex.cpp"
#include "Normal.hpp"
#include "Normal.cpp"

#include <iostream>
#include <cmath>
#include <stdexcept>

namespace asteroids
{

/**
 * @brief   Quaternion representation for OpenGL. Based on: 
 *          http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
 *
 */
template <class T>
class Quaternion {
    private:
        /**
         * @brief   Value of angle, x, y and z
         */
        T m_w, m_x, m_y, m_z;
    
    public:
        /**
         * @brief   Construcs a default quaternion object
         */
        Quaternion();

        /**
         * @brief   Destructor
         */
        ~Quaternion();

        /**
         * @brief   Construcs (with fromAxis()) a quaternion with a given Vertex and an angle
         * @param vec vector
         * @param angle angle
         */
        Quaternion(Vertex<T> vec, T angle);
        
        /**
         * @brief   Constructs a quaternion with three given values and an angle
         * @param x x-value
         * @param y y-value
         * @param z z-value
         * @param w angle
         */
        Quaternion(T x, T y, T z, T w);
        
        /**
         * @brief   Calculates a quaternion with a given vector and an angle
         * @param axis vector
         * @param angle angle
         */
        void fromAxis(Vertex<T> axis, T angle);
        
        /**
         * @brief   Conjugates a quaternion
         * @return quaternion (conjugate)
         */
        Quaternion<T> getConjugate();
        
        /**
         * @brief   Defines the quaternion-quaternion multiplication
         * @param rq quaternion
         * @return quaternion
         */
        Quaternion<T> operator* (Quaternion<T> rq);
        
        /**
         * @brief   Defines the vector-quaternion multiplication
         * @param vec vector
         * @return vector
         */
        Vertex<T> operator* (Vertex<T> vec);
};

}

#endif